package com.ifinc.common.web.frame;

import com.ifinc.common.exception.ConfigException;
import com.ifinc.common.utils.ExceptionUtils;
import com.ifinc.common.utils.StringUtils;
import org.apache.log4j.Logger;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * User: luotao
 * Date: 13-11-28
 * Time: 12:48
 */
public class ClassInfo {

    private static Logger logger = Logger.getLogger(ClassInfo.class);

    private Class clz;

    private Constructor constructor;

    private Map<String, Method> methodMap = new HashMap<String, Method>();

    private String className;

    private String packageName;

    private String fullClassName;

    private Object signal = null;

    public ClassInfo(String packageName, String className) {
        this.packageName = packageName;
        this.className = className;
        if (StringUtils.isEmpty(packageName)) {
            this.fullClassName = packageName + className;
        } else {
            this.fullClassName = packageName + "." + className;
        }

    }

    public boolean loadClassInfo() {
        if (signal == null) {
            synchronized (this) {
                if (signal == null) {
                    try {
                        logger.info("loading class,fullClassName:" + fullClassName);
                        clz = Class.forName(fullClassName);
                        constructor = clz.getConstructor();
                        constructor.setAccessible(true);
                        Method[] methods = clz.getDeclaredMethods();
                        for (Method method : methods) {
                            method.setAccessible(true);
                            methodMap.put(method.getName(), method);
                        }
                        signal = new Object();
                    } catch (ClassNotFoundException e) {
                        ExceptionUtils.printException(e);
                        return false;
                    } catch (NoSuchMethodException e) {
                        ExceptionUtils.printException(e);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public Object newInstance() {
        try {
            return clz.newInstance();
        } catch (InstantiationException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        } catch (IllegalAccessException e) {
            ExceptionUtils.printException(e);
            throw new RuntimeException(e.toString());
        }
    }

    public Object invokeMethod(Object srcObject, String methodName) {
        try {
            Method method = methodMap.get(methodName);
            return method.invoke(srcObject, null);
        } catch (IllegalAccessException e) {
            ExceptionUtils.printException(e);
            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
        } catch (InvocationTargetException e) {
            ExceptionUtils.printException(e);
            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
        }
//        try {
//            return MethodUtils.invokeMethod(srcObject, methodName, null);
//        } catch (NoSuchMethodException e) {
//            ExceptionUtils.printException(e);
//            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
//        } catch (IllegalAccessException e) {
//            ExceptionUtils.printException(e);
//            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
//        } catch (InvocationTargetException e) {
//            ExceptionUtils.printException(e);
//            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
//        }
    }

    public Method getMethod(String methodName) {
        Method method = methodMap.get(methodName);
        if (method == null) {
            throw new ConfigException("not found method : %s, in class : %s", methodName, fullClassName);
        }
        return method;
    }

    public String getFullClassName() {
        return fullClassName;
    }


}
